package com.service.calculate.vehicle;

import com.service.bean.device.Sensor;
import com.service.bean.device.Vehicle;
import com.service.bean.point.Point;
import com.service.bean.signal.GpsSignal;

import java.util.Date;

import com.service.bean.area.Area;
import com.service.bean.data.Data;
import com.service.cache.CacheManager;
import com.service.other.Coordinate;
import com.service.other.Logger;
import com.service.socket.protocol.DataProtocol;
import com.service.tools.DateFormat;
import com.service.tools.Tools;

public class SignalCreator {
	
	private Vehicle vehicle = null;
	
	private Data data = null;
	
	private GpsSignal bean = null;
	
	private BasalCalculator basal = null;
	
	private StatusCalculator status = null;
	
	public SignalCreator(String dataArea,String deviceNo){
		this.vehicle = CacheManager.instance().getVehicle(deviceNo);
		// 不同的协议版本对应不同的处理方法
		this.data = DataProtocol.Parser(dataArea, vehicle.device.version);
		this.bean = new GpsSignal();
		this.bean.gpsNo = deviceNo;
		this.bean.equipmentId = vehicle.equipmentId;
		this.bean.companyCode = vehicle.company.code;
		this.basal = new BasalCalculator();
		this.status = new StatusCalculator();
	}

	/**
	 * 构造函数
	 * @param signal
	 * @param vehicle
	 */
	public SignalCreator(GpsSignal signal,Vehicle vehicle){
		try{
			this.vehicle = vehicle;
			this.bean = signal;
		}catch(Exception e){
			Logger.err(e);
		}
	}

	
	/**
	 * 初步解析, 只解析基础值、状态位、工作状态、经纬度转换和所在区域
	 * @return
	 */
	public GpsSignal createSignal() {
		basal.calculate(data, bean);
		status.calculate(data, bean);
		this.calculateWorkStatus();
		this.calculateCoordinate();
		this.calculateArea();
		this.calculateSprinklingWater();
		// 还没有启动正式的计算，这里为了前端显示，相关字段先暂时使用上一条的数据
		if (vehicle.lastGps != null) {
			bean.IsOutWork = vehicle.lastGps.IsOutWork;
			bean.oilAmtCal = vehicle.lastGps.oilAmtCal;
			bean.oilAmtCal2 = vehicle.lastGps.oilAmtCal2;
			bean.oilAmtCal3 = vehicle.lastGps.oilAmtCal3;
			bean.todayMile = vehicle.lastGps.todayMile;
			bean.todayMile2 = vehicle.lastGps.todayMile2;
			bean.totalMile = vehicle.lastGps.totalMile;
			bean.totalMile2 = vehicle.lastGps.totalMile2;
		}
		return bean;
	}

	/**
	 * 计算非工作状态、油量、里程的变化量
	 * @param signal
	 * @param vehicle
	 */
	public void createSignalInScalarCal(){
		try{
			this.subSpeedAlarm(vehicle, bean);
			this.calculateOutWorkStatus();
			this.calculateOilAmt();
			this.calculateMile();
			this.gpsDrift();
		}catch(Exception e){
			Logger.err(e);
		}
	}

	/**
	 * 如果根据时长，距离超过120公里/小时，那么当前的gps坐标取上一条
	 * 如果持续时间超过10分钟，不过滤
	 */
	private void gpsDrift() {
		if (vehicle != null && vehicle.lastGps != null) {
			double timeDiff = (bean.gpsTime.getTime() - vehicle.lastGps.gpsTime.getTime()) / 1000.00;
			double distance = Tools.getTwoPointDistance(vehicle.lastGps.baiduLng, vehicle.lastGps.baiduLat,
					bean.baiduLng, bean.baiduLat);
			if (timeDiff > 0 ) {
				double speed = distance / timeDiff;
				if (speed > 120 * 1000.00 / 3600 && vehicle.lastGps.durationtime < 10 * 60) {
					bean.lng = vehicle.lastGps.lng;
					bean.lat = vehicle.lastGps.lat;
					bean.baiduLng = vehicle.lastGps.baiduLng;
					bean.baiduLat = vehicle.lastGps.baiduLat;
					bean.durationtime = vehicle.lastGps.durationtime + timeDiff;
				} else {
					bean.durationtime = 0;
				}
			}
		}
	}

	// 副发转速报警(秒):累计时间
	private void subSpeedAlarm(Vehicle vehicle, GpsSignal signal) {
		// 前后副发速度>0，间隔时间<5分钟
		if (vehicle.lastGps != null
				&& (vehicle.lastGps.subSpeed > 0 && signal.subSpeed > 0)
				&& ((signal.gpsTime.getTime() - vehicle.lastGps.gpsTime
						.getTime()) / 1000L < 5 * 60)) {
			long gapTime = (signal.gpsTime.getTime() - vehicle.lastGps.gpsTime
					.getTime()) / 1000L;
			long nextTime = CacheManager.instance().subSpeedMap
					.get(signal.gpsNo) == null ? 0
					: CacheManager.instance().subSpeedMap.get(signal.gpsNo);
			long count = gapTime + nextTime;
			CacheManager.instance().subSpeedMap.put(signal.gpsNo, count);
		}
	}

	/**
	 * 工作状态计算
	 * @param bean
	 */
	private void calculateWorkStatus() {
		if (vehicle != null && vehicle.kindCode != null) {
			if (bean.accStatus == 1) {
				if ("01".equals(vehicle.kindCode) || "04".equals(vehicle.kindCode) || "02".equals(vehicle.kindCode)
						|| "05".equals(vehicle.kindCode) || "15".equals(vehicle.kindCode)
						|| "08".equals(vehicle.kindCode) || "03".equals(vehicle.kindCode)
						|| "07".equals(vehicle.kindCode)) {
					// 01扫路车,04洗扫车,02洒水车,05高压冲洗车,15清洗车,08转运车,03压缩车,07餐厨车
					// ACC开 &（取力器开or副发>500r/min）
					if ((bean.subSpeed > 500 && vehicle.sensorMap.containsKey("130"))
							|| (bean.strengthStatus == 1 && vehicle.sensorMap.containsKey("140"))) {
						bean.isInWork = 1;
					}
					if ("08".equals(vehicle.kindCode) || "03".equals(vehicle.kindCode)
							|| "07".equals(vehicle.kindCode)) {
						// 08转运车,03压缩车,07餐厨车 (ACC开 & V>5km/h)
						if (bean.speed > 5) {
							bean.isInWork = 1;
						}
					}
				} else if ("10".equals(vehicle.kindCode)) {
					// 10垃圾桶转运车 ACC开 & V>5km/h
					if (bean.speed > 5) {
						bean.isInWork = 1;
					}
				} else {
					bean.isInWork = 1;
				}
			}
		}
	}
	
	/**
	 * 油位计算
	 * @param data
	 * @param bean
	 */
	private void calculateOilAmt(){
		
		//如果传过来的油位百分比(高度)大于油箱高度，则当前油位等于上一条油位高度
		if(null != vehicle.oilBox && bean.oilHeight>vehicle.oilBox.oilBoxHight){
			if(null!=vehicle.lastGps){
				bean.oilAmtCal = vehicle.lastGps.oilAmtCal;
				bean.oilAmt = vehicle.lastGps.oilAmt;
				bean.oilAmtCal2 = vehicle.lastGps.oilAmt2;
				bean.oilAmtCal3 = vehicle.lastGps.oilAmt3;
			}else{
				bean.oilAmtCal = 0;
				bean.oilAmt = 0;
				bean.oilAmtCal2 = 0;
				bean.oilAmtCal3 = 0;
			}
			return;
		}
		
		boolean isCal = false;
		if (null != vehicle.oilBox && null != vehicle.oilBox.standards && 0 != vehicle.oilBox.standards.size()) {
			//油量
			double oilAmtCal = CalculatorOil.getOilValue(vehicle, bean.oilHeight);
			if (null == vehicle.lastGps) {
				bean.oilAmtCal = oilAmtCal;
				//实际油位百分比 = 油位高度/邮箱高度
				bean.oilAmt = bean.oilHeight*100/vehicle.oilBox.oilBoxHight;
			} else {
				bean.oilAmtCal = (oilAmtCal == 0) ? vehicle.lastGps.oilAmtCal : oilAmtCal;
				//实际油位百分比 = 油位高度/邮箱高度
				bean.oilAmt = (bean.oilHeight == 0) ? vehicle.lastGps.oilAmt : bean.oilHeight*100/vehicle.oilBox.oilBoxHight;
			}
			isCal = true;
		}
		Sensor oilSensor = vehicle.sensorMap.get("10");
		if(oilSensor != null && oilSensor.isOilSensor()){
			if (null != vehicle.oilBox){
				if(!isCal){
					bean.oilAmtCal = getOilNuber(bean.oilHeight, oilSensor);
				}
				bean.oilAmtCal2=getOilNuber(bean.oilAmt2, oilSensor);
				bean.oilAmtCal3=getOilNuber(bean.oilAmt3, oilSensor);
			}
			if(bean.accStatus == 0 && "HIGH".equals(oilSensor.oilMode) && bean.oilHeight==100){
				bean.oilAmtCal =0;
			}
		}else{
			if (null != vehicle.oilBox){
				if(!isCal){
					bean.oilAmtCal = vehicle.oilBox.oilBoxBulk*bean.oilHeight/100.0;
				}
				bean.oilAmtCal2 = vehicle.oilBox.oilBoxBulk*bean.oilAmt2/100.0;
				bean.oilAmtCal3 = vehicle.oilBox.oilBoxBulk*bean.oilAmt3/100.0;
			}
		}
	}
	
	/**
	 * 里程变化计算
	 * @param bean
	 */
	private void calculateMile() {
		if (vehicle != null) {
			// 从来没有过定位数据(例如：新安装的车辆接入时)
			if (vehicle.lastGps == null) {
				bean.todayMile = 0.00;
				bean.todayMile2 = 0.00;
				bean.totalMile = vehicle.totalMile;
				bean.totalMile2 = vehicle.totalMile2;
//				vehicle.lastGps = new GpsSignal(vehicle.device.deviceNo);
			} else {
				// 如果最后一条定位数据时间与当前GPS时间是同一天
				if (vehicle.lastGps.gpsTime != null && DateFormat.format(vehicle.lastGps.gpsTime, "yyyy-MM-dd").equals(DateFormat.format(bean.gpsTime, "yyyy-MM-dd"))) {
					// 如果当前是非定位数据，则使用上一条GPS数据的里程信息
					if (bean.gpsStatus==0) {
						bean.todayMile = vehicle.lastGps.todayMile;
						bean.todayMile2 = vehicle.lastGps.todayMile2;
						bean.totalMile = vehicle.lastGps.totalMile;
						bean.totalMile2 = vehicle.lastGps.totalMile2;
					} else { // 如果当前是定位数据，则使用计算逻辑
						double mileChange = bean.curMile - vehicle.lastGps.curMile;
						double mileChange2 = bean.curMile2 - vehicle.lastGps.curMile2;
						if (mileChange >= 0) {
							bean.todayMile = vehicle.lastGps.todayMile + mileChange;
							bean.totalMile = vehicle.lastGps.totalMile + mileChange;
						} else {
							bean.todayMile = vehicle.lastGps.todayMile;
							bean.totalMile = vehicle.lastGps.totalMile;
						}
						if (mileChange2 >= 0) {
							bean.todayMile2 = vehicle.lastGps.todayMile2 + mileChange2;
							bean.totalMile2 = vehicle.lastGps.totalMile2 + mileChange2;
						} else {
							bean.todayMile2 = vehicle.lastGps.todayMile2;
							bean.totalMile2 = vehicle.lastGps.totalMile2;
						}
					}
				} else { // 如果最后一条定位数据时间与当前GPS时间不是同一天(例如：今天的第一条GPS)
					bean.todayMile = 0.00;
					bean.todayMile2 = 0.00;
					bean.totalMile = vehicle.lastGps.totalMile;
					bean.totalMile2 = vehicle.lastGps.totalMile2;
				}
			}
			// 计算完成后，更新vehicle.lastGps
			//vehicle.lastGps = bean
		}
	}
	
	private double getOilNuber(double oilAmt,Sensor oilSensor){
	  	double oil=0;
		oil=(oilSensor.para1*oilAmt*oilAmt*oilAmt+oilSensor.para2*oilAmt*oilAmt+oilSensor.para3*oilAmt+oilSensor.para4)/100*vehicle.oilBox.oilBoxBulk;
		return oil;
	}
	
	/**
	 * gps坐标转百度坐标
	 */
	private void calculateCoordinate(){
		Point p = new Point(bean.lat,bean.lng);
		p = Coordinate.gpsToWgs84(p);
		p = Coordinate.wgs84ToBd09(p);
		bean.baiduLat = p.baiduLat;
		bean.baiduLng = p.baiduLng;
		bean.isPosition = 1;
		//new BaiduApiAddress().getAddress(bean);
	}
	
	/**
	 * 计算车辆是否在某个区域中
	 */
	private void calculateArea(){
		if (vehicle != null) {
			Point p = new Point(bean.baiduLat,bean.baiduLng);
			for (Area area : vehicle.getAreas().values()) {
				if(area.isInArea(p)){
					bean.areaId = area.id;
					break;
				}
			}
		}
	}
	
	/**
	 * 非工作状态计算
	 */
	private void calculateOutWorkStatus(){
		if (vehicle == null || vehicle.lastGps == null) {
			// 从来没有过定位数据(例如：新安装的车辆接入时)
			bean.IsOutWork = 0;
			return;
		}
		
		// 如果最后一条定位数据时间与当前GPS时间是同一天
		if (vehicle.lastGps.gpsTime != null && DateFormat.format(vehicle.lastGps.gpsTime, "yyyy-MM-dd").equals(DateFormat.format(bean.gpsTime, "yyyy-MM-dd"))) {
			bean.IsOutWork = (vehicle.lastGps.IsOutWork == 1)?1:bean.isInWork;
		} else { // 如果最后一条定位数据时间与当前GPS时间不是同一天(例如：今天的第一条GPS)
			bean.IsOutWork = 0;
		}
	}
	
//	/**
//	 * 车辆报警
//	 */
//	private void calculateAlarm(){
//		AlarmInfo ai = null;
//		for(AlarmRule rule : vehicle.alarmRuleMap.values()){
//			try {
//				ai = rule.doAlarm(vehicle, bean);
//				if (null != ai) {
//					CacheManager.instance().getAlarmSaveQueue(vehicle.company).offer(ai);
//				}
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//		}
//	}
	/**
	 * 洒水量计算
	 * @param bean
	 */
	private void calculateSprinklingWater() {
		double d = bean.majSpeed;
		bean.sprinklingWater = 0;
		// 工作状态下 && 喷水
		if (bean.isInWork == 1 && bean.wateringStatus != 0) {
			// 此处==1000K*rL/60R （K=转速比，r=FO获取的转速r/min，L=泵排量m3/h，R=泵的额定转速）
			bean.sprinklingWater = vehicle.rotationalSpeed != 0
					? 1000 * vehicle.pumpRated * d * vehicle.pumpDelivery / (60 * vehicle.rotationalSpeed) : 0;
		}
	}

	/**
	 * 判断车辆当前是否处于工作(排班)时间中
	 * @param isJudgeFloat 是否判断浮动时间</br>true: 判断浮动时间</br>false: 不判断浮动时间
	 * @param vehicle
	 * @param signal
	 */
	public static boolean calIsInWorkTime(
			boolean isJudgeFloat, Vehicle vehicle, GpsSignal signal) {
		if (null == vehicle || null == vehicle.duty) {
			return false;
		}
		Date start = null;
		Date end = null;
		if (isJudgeFloat) {
			/* 若需要判断浮动时间，则默认浮动时间为1分钟 */
			int startFloat = 1,
				endFloat = 1;
			if (vehicle.duty.startFloatTime != 0)
				startFloat = vehicle.duty.startFloatTime;
			if (vehicle.duty.endFloatTime != 0)
				endFloat = vehicle.duty.endFloatTime;
			start = new Date(vehicle.duty.workStartTime.getTime() - startFloat * 60 * 1000);
			end = new Date(vehicle.duty.workEndTime.getTime() + endFloat * 60 * 1000);
		} else {
			start = vehicle.duty.workStartTime;
			end = vehicle.duty.workEndTime;
		}
		if (signal.gpsTime.after(start) && signal.gpsTime.before(end))
			return true;
		else
			return false;
	}
	
}
